package cn.springcloud.fix.stomp.config;

import cn.springcloud.fix.stomp.component.WsHeaderInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.socket.config.annotation.*;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Configuration
@EnableWebSocketMessageBroker // 可以快速地启用WebSocket消息代理功能
public class WebsocketConfig implements WebSocketMessageBrokerConfigurer {

    private static final long HEART_BEAT = 10000;

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        ThreadPoolTaskScheduler te = new ThreadPoolTaskScheduler();
        te.setPoolSize(1);
        te.setThreadNamePrefix("wss-heartbeat-thread-");
        te.initialize();

        registry.enableSimpleBroker("/topic", "/queue")
                .setHeartbeatValue(new long[]{HEART_BEAT, HEART_BEAT})
                .setTaskScheduler(te);

        // 客户端向服务端发消息前缀，表示所有以/app开头的客户端消息或请求都会路由到带有 @MessageMapping 注解的方法中
        registry.setApplicationDestinationPrefixes("/app");

        // 一对一消息前缀， 客户端接收一对一消息需要配置的前缀 如 '/user/{userid}/message'
        registry.setUserDestinationPrefix("/user");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws")
                .setAllowedOrigins("*")
                .withSockJS()
                .setDisconnectDelay(TimeUnit.SECONDS.toMillis(60));
    }

    /**
     * 配置发送与接收的消息参数，可以指定消息字节大小，缓存大小，发送超时时间
     * 1. setMessageSizeLimit 设置消息缓存的字节数大小 字节
     * 2. setSendBufferSizeLimit 设置websocket会话时，缓存的大小 字节
     * 3. setSendTimeLimit 设置消息发送会话超时时间，毫秒
     */
    @Override
    public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
        registration.setMessageSizeLimit(10240).setSendBufferSizeLimit(10240).setSendTimeLimit(10000);
    }

    /**
     * 设置输入消息通道的线程数，默认线程为1，可以自己自定义线程数，最大线程数，线程存活时间
     */
    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.interceptors(headerParamInterceptor());
        registration.taskExecutor().corePoolSize(10).maxPoolSize(20).keepAliveSeconds(60);
    }

    /**
     * 设置输出消息通道的线程数，默认线程为1，可以自己自定义线程数，最大线程数，线程存活时间
     */
    @Override
    public void configureClientOutboundChannel(ChannelRegistration registration) {
        registration.taskExecutor().corePoolSize(10).maxPoolSize(20).keepAliveSeconds(60);
    }

    @Bean
    public ScheduledThreadPoolExecutor scheduledThreadPoolExecutor() {
        return new ScheduledThreadPoolExecutor(5);
    }

    @Bean
    public ChannelInterceptor headerParamInterceptor() {
        return new WsHeaderInterceptor();
    }
}
